package cn.coisini.service.impl;

import cn.coisini.mapper.ArticleMapper;
import cn.coisini.mapper.RoleMapper;
import cn.coisini.mapper.UserMapper;
import cn.coisini.mapper.UserRoleMapper;
import cn.coisini.model.common.constants.RedisConstants;
import cn.coisini.model.common.dtos.Result;
import cn.coisini.model.common.enums.ResultEnum;
import cn.coisini.model.common.exception.CustomAuthenticationException;
import cn.coisini.model.common.log.service.AsyncLoginLogService;
import cn.coisini.model.dto.UserDto;
import cn.coisini.model.pojo.Role;
import cn.coisini.model.pojo.User;
import cn.coisini.model.pojo.UserRole;
import cn.coisini.model.vo.AssginRoleVo;
import cn.coisini.model.vo.QueryVo;
import cn.coisini.model.vo.RouterVo;
import cn.coisini.model.vo.UserVo;
import cn.coisini.service.FileUploadService;
import cn.coisini.service.MenuService;
import cn.coisini.service.UserService;
import cn.coisini.utils.IdWorker;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.coisini.model.common.constants.AdminConstants.*;
import static cn.coisini.utils.JwtUtil.getUserIdFromToken;
import static cn.coisini.utils.JwtUtil.getUsernameFromToken;

/**
 * @author xiangshaw
 * Description: 用户接口实现类
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final RoleMapper roleMapper;
    private final UserRoleMapper userRoleMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final UserMapper userMapper;
    private final MenuService menuService;
    private final PasswordEncoder passwordEncoder;
    private final AsyncLoginLogService asyncLoginLogService;
    private final ArticleMapper articleMapper;

    // 访问地址
    @Value("${file.upload.local.url}")
    private String url;

    // 分页查询
    @Override
    public Result<Object> pagingQuery(QueryVo queryVo) {
        QueryWrapper<User> wrapper = buildQueryWrapper(queryVo);
        // 处理分页逻辑
        Page<User> page = new Page<>(queryVo.getCurrent(), queryVo.getLimit());
        Page<User> userPage = page(page, wrapper);
        Result<Object> result = new Result<>();
        result.setData(userPage);
        result.setHost(url);
        return result;
    }

    // 构建查询条件
    private QueryWrapper<User> buildQueryWrapper(QueryVo queryVo) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // 处理关键字模糊查询
        Optional.ofNullable(queryVo.getKeyword())
                .filter(CharSequenceUtil::isNotBlank)
                .ifPresent(keyword -> wrapper.and(x -> x
                        .like("user_name", keyword)
                        .or()
                        .like("nick_name", keyword)
                        .or()
                        .like("phone", keyword)
                ));
        // 处理时间范围查询
        Optional.ofNullable(queryVo.getCreateTimeBegin())
                .filter(CharSequenceUtil::isNotBlank)
                .ifPresent(startTime -> wrapper.ge("create_time", startTime));
        Optional.ofNullable(queryVo.getCreateTimeEnd())
                .filter(CharSequenceUtil::isNotBlank)
                .ifPresent(endTime -> wrapper.le("create_time", endTime));
        // 删除标记
        wrapper.eq("del_flag", FALSE)
                // 排序
                .orderByDesc("id")
                // 选择性排除password、salt字段
                .select(User.class, info -> !"password".equals(info.getColumn()))
                .select(User.class, info -> !"salt".equals(info.getColumn()));
        return wrapper;
    }

    private final FileUploadService fileUploadService;

    // 删除用户
    @Override
    public Result<ResultEnum> removeUser(String id) {
        // 1.检查参数是否为空
        if (CharSequenceUtil.isBlank(id)) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER);
        }
        // 2.判断当前用户是否存在
        User user = getById(id);
        if (user == null) {
            return Result.error(ResultEnum.DATA_NOT_EXIST);
        }
        // 3.删除头像文件（如果存在）
        String avatar = user.getAvatar();
        if (StringUtils.hasText(avatar)) {
            fileUploadService.localDeleteFile(avatar);
        }
        // 4.删除角色关联（仅当存在关联时）
        Long roleCount = userRoleMapper.selectCount(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, id));
        if (roleCount > 0) {
            userRoleMapper.delete(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, id));
        }
        // 5.删除用户
        boolean b = removeById(id);
        // 6.根据删除结果返回响应
        if (b) {
            return Result.ok(ResultEnum.SUCCESS, "用户删除成功");
        } else {
            return Result.error(ResultEnum.FAIL, "用户删除失败");
        }
    }

    // 批量删除用户
    @Transactional
    @Override
    public Result<ResultEnum> batchRemove(List<String> ids) {
        // 1.检查参数是否为空或为空列表
        if (ids == null || ids.isEmpty()) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER);
        }
        // 2.获取所有要删除的用户详细信息
        List<User> users = listByIds(ids);
        if (users.isEmpty()) {
            return Result.error(ResultEnum.DATA_NOT_EXIST);
        }
        // 3.删除头像文件
        users.stream()
                .map(User::getAvatar)
                .filter(avatar -> avatar != null && !avatar.isEmpty())
                .forEach(avatar -> {
                    try {
                        fileUploadService.localDeleteFile(avatar);
                    } catch (Exception e) {
                        log.error("Failed to delete avatar file: {}", avatar, e);
                    }
                });
        // 4.查询是否存在角色关联
        List<UserRole> userRoles = userRoleMapper.selectList(Wrappers.<UserRole>lambdaQuery().in(UserRole::getUserId, ids));
        if (!userRoles.isEmpty()) {
            // 4.1 存在角色关联时进行删除
            try {
                userRoleMapper.delete(Wrappers.<UserRole>lambdaQuery().in(UserRole::getUserId, ids));
            } catch (Exception e) {
                log.error("Failed to delete user roles for IDs: {}", ids, e);
            }
        }
        // 5.批量删除用户
        int deletedCount;
        try {
            deletedCount = baseMapper.deleteBatchIds(ids);
        } catch (Exception e) {
            log.error("Failed to delete users for IDs: {}", ids, e);
            return Result.error(ResultEnum.FAIL, "用户删除失败");
        }
        // 6.检查删除结果并返回
        if (deletedCount == ids.size()) {
            return Result.ok(ResultEnum.SUCCESS, "用户批量删除成功");
        } else {
            return Result.error(ResultEnum.FAIL, "部分用户删除失败，已删除 " + deletedCount + " 个用户");
        }
    }

    // 添加用户
    @Override
    public Result<ResultEnum> addUser(UserDto userDto) {
        // 1.检查用户名是否已经注册
        if (checkUserAdd(userDto.getUsername())) {
            return Result.error(ResultEnum.DATA_EXIST, "该用户名已经注册");
        }
        // 类型转换为实体
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        user.setId(String.valueOf(new IdWorker().nextId()));
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setCreateTime(LocalDateTime.now());
        // 保存
        if (save(user)) {
            return Result.ok(ResultEnum.SUCCESS, "用户添加成功");
        } else {
            return Result.error(ResultEnum.FAIL, "用户添加失败");
        }
    }

    // 检查用户名是否已经注册
    private boolean checkUserAdd(String username) {
        return userMapper.selectCount(Wrappers.<User>lambdaQuery().eq(User::getUsername, username)) > ACCOUNT_NORMAL;
    }

    // 修改用户信息
    @Override
    public Result<ResultEnum> updateUser(UserDto userDto) {
        User user = new User();
        user.setUsername(userDto.getUsername());
        user.setNickName(userDto.getNickName());
        user.setDescription(userDto.getDescription());
        user.setPhone(userDto.getPhone());
        user.setEmail(userDto.getEmail());
        user.setUpdateTime(LocalDateTime.now());
        if (update(user, Wrappers.<User>lambdaQuery().eq(User::getId, userDto.getId()))) {
            return Result.ok(ResultEnum.SUCCESS, "用户信息修改成功");
        } else {
            return Result.error(ResultEnum.FAIL, "用户信息修改失败");
        }
    }

    // 根据用户ID查询用户信息
    @Override
    public Result<UserDto> findById(String userId) {
        if (CharSequenceUtil.isBlank(userId)) {
            return Result.error(ResultEnum.DATA_NOT_EXIST);
        }
        User user = getById(userId);
        if (user == null) {
            return Result.error(ResultEnum.DATA_NOT_EXIST);
        }
        // 用户信息赋值
        Result<UserDto> result = new Result<>();
        result.setData(assignmentUserInfo(user));
        result.setHost(url);
        return result;
    }

    private UserDto assignmentUserInfo(User user) {
        UserDto userDto = new UserDto();
        userDto.setId(user.getId());
        userDto.setUsername(user.getUsername());
        userDto.setNickName(user.getNickName());
        userDto.setPhone(user.getPhone());
        userDto.setAvatar(user.getAvatar());
        userDto.setEmail(user.getEmail());
        userDto.setDescription(user.getDescription());
        userDto.setStatus(user.getStatus());
        userDto.setCreateTime(user.getCreateTime());
        return userDto;
    }

    // 根据用户ID列表批量获取用户信息
    @Override
    public List<User> findByIds(List<String> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            return Collections.emptyList();
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().in("id", userIds);
        return baseMapper.selectList(queryWrapper);
    }

    // 根据用户ID列表批量获取用户信息，并以用户ID为键构建Map
    @Override
    public Map<String, User> getUserMapByIds(List<String> userIds) {
        List<User> users = findByIds(userIds);
        return users.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    }

    @Override
    public Map<String, Object> findByUsername(String username) {
        // 1.根据用户名查询用户信息
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("user_name", username));
        // 2.根据用户id获取菜单权限值
        List<RouterVo> userMenuList = menuService.findUserMenuList(user.getId());
        HashMap<String, Object> map = new HashMap<>();
        // 3.根据用户id获取按钮权限值
        List<String> userButtonList = menuService.findUserButtonList(user.getId());
        map.put("id", user.getId());
        map.put("username", user.getUsername());
        map.put("password", user.getPassword());
        map.put("avatar", user.getAvatar());
        map.put("userMenuList", userMenuList);
        map.put("userButtonList", userButtonList);
        map.put("email", user.getEmail());
        map.put("phone", user.getPhone());
        map.put("description", user.getDescription());
        map.put("nickName", user.getNickName());
        map.put("host", url);
        return map;
    }

    // 获取用户信息
    @Override
    public Result<Map<String, Object>> getUserInfoByUserName() {
        String username = getUsernameFromToken();
        // 2.根据用户名查询用户信息
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("user_name", username));
        // 2.根据用户id获取菜单权限值
        List<RouterVo> userMenuList = menuService.findUserMenuList(user.getId());
        HashMap<String, Object> map = new HashMap<>();
        // 3.根据用户id获取按钮权限值
        List<String> userButtonList = menuService.findUserButtonList(user.getId());

        // 4.用户注册距今的天数
        long days = ChronoUnit.DAYS.between(user.getCreateTime(), LocalDateTime.now());

        // 5.用户登录IP属地
        // 根据用户ID查询最近的那次登录日志
        String loginIpCity = asyncLoginLogService.getLastLoginLogByUserId(user.getId()).getLoginIpCity();
        loginIpCity = loginIpCity == null ? "未知" : loginIpCity;
        // 6.用户总发布文章数
        long articleCount = articleMapper.getArticleCountByUserId(user.getId(), TRUE);

        map.put("id", user.getId());
        map.put("username", user.getUsername());
        map.put("avatar", user.getAvatar());
        map.put("userMenuList", userMenuList);
        map.put("userButtonList", userButtonList);
        map.put("email", user.getEmail());
        map.put("phone", user.getPhone());
        map.put("description", user.getDescription());
        map.put("nickName", user.getNickName());
        map.put("host", url);
        map.put("period", days);
        map.put("loginIpCity", loginIpCity);
        map.put("articleCount", articleCount);
        return Result.ok(map);
    }

    // 修改用户信息
    @Override
    public Result<ResultEnum> updateUserInfo(UserDto userDto) {
        // 1.获取用户ID
        String userId = getUserIdFromToken();
        if (userId == null) {
            return Result.error(ResultEnum.DATA_NOT_FOUND_BY_USERNAME);
        }
        // 2.查询用户
        User user = getById(userId);
        if (user == null) {
            return Result.error(ResultEnum.DATA_NOT_FOUND_BY_USERNAME);
        }
        // 3.更新用户信息
        user.setNickName(userDto.getNickName());
        user.setPhone(userDto.getPhone());
        user.setEmail(userDto.getEmail());
        user.setDescription(userDto.getDescription());
        user.setUpdateTime(LocalDateTime.now());
        // 4.更新用户信息
        if (updateById(user)) {
            return Result.ok(ResultEnum.SUCCESS);
        }
        return Result.error(ResultEnum.FAIL, "信息修改失败");
    }

    // 更新用户状态
    @Override
    public Result<ResultEnum> updateUserStatus(Integer status) {
        // 1.检查参数是否在指定范围
        if (status == null || status < ACCOUNT_NORMAL || status > ACCOUNT_SUSPENDED) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER, "状态值错误，请检查参数是否正确");
        }
        // 2.获取用户ID
        String userId = getUserIdFromToken();
        if (CharSequenceUtil.isBlank(userId)) {
            return Result.error(ResultEnum.TOKEN_EXCEPTION);
        }
        // 3.更新用户状态
        boolean updateUserStatus = update(Wrappers.<User>lambdaUpdate().eq(User::getId, userId).set(User::getStatus, status));
        // 4.返回结果
        return updateUserStatus ? Result.ok(ResultEnum.SUCCESS) : Result.error(ResultEnum.FAIL, "状态修改失败");
    }

    // 更新用户头像
    @Override
    public Result<ResultEnum> updateUserAvatar(String avatar) {
        // 1.检查参数
        if (CharSequenceUtil.isBlank(avatar)) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER, "头像不能为空");
        }
        // 2.获取用户ID
        String userId = getUserIdFromToken();
        if (CharSequenceUtil.isBlank(userId)) {
            return Result.error(ResultEnum.DATA_NOT_FOUND_BY_USERNAME);
        }
        // 4.更新用户头像
        boolean updateUserAvatar = update(Wrappers.<User>lambdaUpdate().eq(User::getId, userId)
                .set(User::getAvatar, avatar)
                .set(User::getUpdateTime, LocalDateTime.now()));
        return updateUserAvatar ? Result.ok(ResultEnum.SUCCESS) : Result.error(ResultEnum.FAIL, "头像修改失败");
    }

    // 获取用户密码
    @Override
    public String getUserPassword(String id) {
        return getById(id).getPassword();
    }

    // 更新用户密码
    @Override
    public Result<ResultEnum> updateUserPassword(UserVo userVo) {
        String oldPassword = userVo.getOldPassword();
        String newPassword = userVo.getNewPassword();
        String confirmPassword = userVo.getConfirmPassword();
        String phone = userVo.getPhone();
        String confirmCode = userVo.getConfirmCode();
        String newPhone = userVo.getNewPhone();
        String newConfirmCode = userVo.getNewConfirmCode();

        // 1.检查用户ID
        String userId = getUserIdFromToken();
        if (CharSequenceUtil.isBlank(userId)) {
            return Result.error(ResultEnum.DATA_NOT_FOUND_BY_USERNAME);
        }

        // 2. 检查参数是否为空
        boolean passwordUpdate = Stream.of(oldPassword, newPassword, confirmPassword).anyMatch(CharSequenceUtil::isBlank);
        boolean verifyPhone = Stream.of(phone, confirmCode).anyMatch(CharSequenceUtil::isBlank);
        boolean phoneUpdate = Stream.of(newPhone, newConfirmCode).anyMatch(CharSequenceUtil::isBlank);

        if (passwordUpdate && verifyPhone && phoneUpdate) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER, "参数错误");
        }

        if (!passwordUpdate) {
            // 2. 检查新密码与确认密码是否一致
            if (!newPassword.equals(confirmPassword)) {
                return Result.error(ResultEnum.DATA_INVALID_PARAMETER, "两次密码输入不一致");
            }

            // 4. 验证旧密码
            String userPassword = getUserPassword(userId);
            if (userPassword == null || !passwordEncoder.matches(oldPassword, userPassword)) {
                return Result.error(ResultEnum.DATA_INVALID_PARAMETER, "旧密码错误");
            }
            // 5. 更新密码
            boolean isPasswordUpdated = updatePassword(userId, newPassword);
            if (isPasswordUpdated) {
                // 5.1删除redis中对应的token
                stringRedisTemplate.delete(userId);
                return Result.ok(ResultEnum.SUCCESS);
            } else {
                return Result.error(ResultEnum.FAIL, "密码修改失败");
            }
        }
        if (!verifyPhone) {
            // 检验用户是否绑定了手机号
            if (checkUserBindPhone(phone)) {
                // 检验验证码
                checkCode(userVo.getPhone(), userVo.getConfirmCode());
                return Result.ok(ResultEnum.SUCCESS, "手机号检验通过");
            } else {
                return Result.error(ResultEnum.DATA_NOT_EXIST, "用户未绑定手机号");
            }
        }
        if (!phoneUpdate) {
            // 检验验证码
            checkCode(userVo.getNewPhone(), userVo.getNewConfirmCode());
            // 检查新手机号是否已绑定
            if (checkUserPhone(newPhone)) {
                return Result.error(ResultEnum.DATA_EXIST, "新手机号已绑定账号");
            }
            // 更新手机号
            boolean updated = update(Wrappers.<User>lambdaUpdate()
                    .eq(User::getId, userId)
                    .set(User::getPhone, newPhone)
                    .set(User::getUpdateTime, LocalDateTime.now()));
            if (updated){
                stringRedisTemplate.delete(RedisConstants.MOBILE_CODE_PREFIX + newPhone);
                return Result.ok(ResultEnum.SUCCESS, "手机号换绑成功");
            }
            return Result.error(ResultEnum.FAIL, "手机号换绑失败");
        }
        return Result.error(ResultEnum.DATA_INVALID_PARAMETER, "参数错误");
    }

    // 绑定手机号
    private Result<ResultEnum> updateUserPhone(String userId, String phone) {
        // 检查手机号是否已存在
        if (checkUserPhone(phone)) {
            return Result.error(ResultEnum.DATA_EXIST, "手机号已被绑定");
        }
        boolean updated = update(Wrappers.<User>lambdaUpdate()
                .eq(User::getId, userId)
                .set(User::getPhone, phone)
                .set(User::getUpdateTime, LocalDateTime.now()));
        if (updated){
            stringRedisTemplate.delete(RedisConstants.MOBILE_CODE_PREFIX + phone);
            return Result.ok(ResultEnum.SUCCESS, "手机号绑定成功");
        }
        return Result.error(ResultEnum.FAIL, "手机号绑定失败");
    }

    /**
     * 绑定手机号
     */
    @Override
    public Result<ResultEnum> bindPhone(UserVo userVo) {
        if (checkUserPhone(userVo.getBindPhone())) {
            return Result.error(ResultEnum.DATA_EXIST, "手机号已被绑定");
        }
        // 核查缓存验证码
        checkCode(userVo.getBindPhone(), userVo.getBindConfirmCode());
        return update(Wrappers.<User>lambdaUpdate()
                .eq(User::getId, getUserIdFromToken())
                .set(User::getPhone, userVo.getBindPhone())
                .set(User::getUpdateTime, LocalDateTime.now()))
                ? Result.ok(ResultEnum.SUCCESS) : Result.error(ResultEnum.FAIL, "手机号绑定失败");
    }

    /**
     * 检查手机号是否已存在
     *
     * @param phone 手机号
     */
    @Override
    public boolean checkUserPhone(String phone) {
        return count(Wrappers.<User>lambdaQuery()
                .eq(User::getPhone, phone)
        ) > 0;
    }

    /**
     * 检查用户是否绑定了手机号
     *
     * @param phone
     */
    private boolean checkUserBindPhone(String phone) {
        return count(Wrappers.<User>lambdaQuery()
                .eq(User::getId, getUserIdFromToken())
                .eq(User::getPhone, phone)
        ) > 0;
    }

    /**
     * 验证验证码
     *
     * @param phone       手机号
     * @param confirmCode 验证码
     */
    private void checkCode(String phone, String confirmCode) {
        String code = stringRedisTemplate.opsForValue().get(RedisConstants.MOBILE_CODE_PREFIX + phone);
        if (code == null || CharSequenceUtil.isBlank(code)) {
            throw new CustomAuthenticationException(ResultEnum.DATA_INVALID_PARAMETER, "手机号或验证码错误");
        }
        if (!code.equals(confirmCode)) {
            throw new CustomAuthenticationException(ResultEnum.DATA_INVALID_PARAMETER, "手机号或验证码错误");
        }
    }

    // 更新密码
    private boolean updatePassword(String userId, String newPassword) {
        return update(Wrappers.<User>lambdaUpdate()
                .eq(User::getId, userId)
                .set(User::getPassword, passwordEncoder.encode(newPassword))
                .set(User::getUpdateTime, LocalDateTime.now()));
    }

    // 获取用户id获取角色数据
    @Override
    public Result<Map<String, Object>> getRolesByUserId(String id) {
        // 1.检查参数
        if (id == null) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER);
        }
        // 2.获取所有角色
        List<Role> roleList = roleMapper.selectList(null);
        // 3.根据用户id查询已经分配的角色
        List<UserRole> userRoleList = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", id));
        // 4.获取所有角色id
        List<String> roleIds = userRoleList.stream().map(UserRole::getRoleId).toList();
        // 5.封装到map
        HashMap<String, Object> map = new HashMap<>();
        // 5.1 所有角色
        map.put("allRoles", roleList);
        // 5.2 用户分配角色id集合
        map.put("userRoleIds", roleIds);
        return Result.ok(map);
    }

    // 给用户分配角色
    @Override
    public Result<ResultEnum> doAssign(AssginRoleVo assginRoleVo) {
        // 1.检查参数
        if (assginRoleVo.getUserId() == null) {
            return Result.error(ResultEnum.DATA_INVALID_PARAMETER);
        }
        // 2.根据用户id删除原来分配的角色
        userRoleMapper.delete(new QueryWrapper<UserRole>().eq("user_id", assginRoleVo.getUserId()));
        // 3.获取所有角色id，添加角色用户关系表
        List<String> roleIdList = assginRoleVo.getRoleIdList();
        roleIdList.forEach(roleId -> {
            UserRole userRoleEntity = new UserRole();
            userRoleEntity.setUserId(assginRoleVo.getUserId());
            userRoleEntity.setRoleId(roleId);
            userRoleMapper.insert(userRoleEntity);
        });
        return Result.ok(ResultEnum.SUCCESS);
    }

    // 获取用户名
    @Override
    public Map<String, String> getUserNamesByIds(List<String> userIds) {
        // 批量查询用户信息
        List<User> users = userMapper.selectBatchIds(userIds);
        return users.stream()
                .collect(Collectors.toMap(User::getId, User::getUsername));
    }
}
